/**
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.

 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package core.icq;

import core.Main;
import java.util.Date;
import core.GlobalConfig;
import core.ProxyConnection;

import ru.caffeineim.protocols.icq.core.OscarConnection;
import ru.caffeineim.protocols.icq.integration.OscarInterface;
import ru.caffeineim.protocols.icq.integration.events.ContactListEvent;
import ru.caffeineim.protocols.icq.integration.events.IncomingMessageEvent;
import ru.caffeineim.protocols.icq.integration.events.IncomingUrlEvent;
import ru.caffeineim.protocols.icq.integration.events.IncomingUserEvent;
import ru.caffeineim.protocols.icq.integration.events.LoginErrorEvent;
import ru.caffeineim.protocols.icq.integration.events.MessageAckEvent;
import ru.caffeineim.protocols.icq.integration.events.MessageErrorEvent;
import ru.caffeineim.protocols.icq.integration.events.MessageMissedEvent;
import ru.caffeineim.protocols.icq.integration.events.OffgoingUserEvent;
import ru.caffeineim.protocols.icq.integration.events.OfflineMessageEvent;
import ru.caffeineim.protocols.icq.integration.events.SsiAuthReplyEvent;
import ru.caffeineim.protocols.icq.integration.events.SsiAuthRequestEvent;
import ru.caffeineim.protocols.icq.integration.events.SsiFutureAuthGrantEvent;
import ru.caffeineim.protocols.icq.integration.events.SsiModifyingAckEvent;
import ru.caffeineim.protocols.icq.integration.events.StatusEvent;
import ru.caffeineim.protocols.icq.integration.listeners.ContactListListener;
import ru.caffeineim.protocols.icq.integration.listeners.MessagingListener;
import ru.caffeineim.protocols.icq.integration.listeners.OurStatusListener;
import ru.caffeineim.protocols.icq.integration.listeners.UserStatusListener;
import ru.caffeineim.protocols.icq.setting.enumerations.StatusModeEnum;
import tools.Logger;



/**
 * <p>Created by 22.03.2008
 *   @author Samolisov Pavel && DCRM
 */
public class CoreICQ implements MessagingListener, UserStatusListener, OurStatusListener, ContactListListener, Runnable  {

    private String SERVER = "login.icq.com";
    private int PORT = 5190;
    private String UIN = "";
    private String PASSWORD = "";
    private ProxyConnection proxyConnection;

    public OscarConnection connection;

    public String MASTER_UIN = "";
    public String WELCOME_MSG="";

    private Thread thread;
    //private ContactListListener cll;

    public CoreICQ(String uin, String password, String server, int port, String m_uin,ProxyConnection proxyConnection) {
        this.SERVER=server;
        this.PORT=port;
        this.UIN=uin;
        this.PASSWORD=password;
        this.MASTER_UIN=m_uin;
        this.proxyConnection=proxyConnection;

        thread = new Thread(this);
        thread.setName("CoreICQ["+UIN+"]");
        thread.start();
        //Main.startCoreSpam();
    }

    public void onIncomingMessage(IncomingMessageEvent e) {
        //Logger.writelnErr(e.getSenderID() + " sent : " + e.getMessage());
        try {
        //OscarInterface.sendBasicMessage(connection, MASTER_UIN, "Инфхель Онлайн "+FucLib.getDiffTime(TIME_START, new Date().getTime()));
            if (GlobalConfig.F_LOG_MSG) {Main.pr("ICQ["+e.getSenderID().toString()+"->"+e.getMessage().toString()+"]\n",true);}
            new IncomeMsg(e,this);
            if (GlobalConfig.F_BACK_MSG) {OscarInterface.sendBasicMessage(this.connection, MASTER_UIN, e.getSenderID().toString()+"->"+e.getMessage().toString());}
            
        }
        catch (Exception ex) {Logger.writelnErr(ex.getMessage());}
    }

    public void onIncomingUrl(IncomingUrlEvent e) {
        Logger.writelnErr(e.getSenderID() + " sent : " + e.getUrl());
    }

    public void onOfflineMessage(OfflineMessageEvent e) {
        if (GlobalConfig.F_DEBUG_MSG) {
            System.err.println(e.getSenderUin() + " sent new offline message");
            System.err.println(" text: " + e.getMessage());
            System.err.println(" date: " + e.getSendDate());
            System.err.println(" type: " + e.getMessageType());
            System.err.println(" flag: " + e.getMessageFlag());
        }
    }

    public void onOffgoingUser(OffgoingUserEvent e) {
         Logger.writelnErr(e.getOffgoingUserId() + " went offline.");
    }

    public void onIncomingUser(IncomingUserEvent e) {
         Logger.writelnErr(e.getIncomingUserId() + " has just signed on.");
    }

    public void onMessageMissed(MessageMissedEvent e) {
	 Logger.writelnErr("Message from " + e.getUin() + " can't be recieved because " + e.getReason());
    }

    public void onMessageError(MessageErrorEvent e) {
         Logger.writelnErr("Message error code " + e.getError() + " occurred");
    }

    public void disconnect(boolean exit) {
        try {
            Logger.writelnErr("Init disconnect");
            OscarInterface.changeStatus(this.connection, new StatusModeEnum(StatusModeEnum.OFFLINE));
            try {
                this.connection.getClient().disconnect();
            } catch (Exception ex0) { Logger.writelnErr(ex0.getMessage()); }
            Thread.sleep(4000);
            this.connection.removeOurStatusListener(this);
            this.connection.removeUserStatusListener(this);
            this.connection.removeMessagingListener(this);
            this.connection.close();
            if (exit) Main.exit();
        } catch (Exception ex) { Logger.writelnErr(ex.getMessage()); }
    }

    public void reConnect() {
        try {
            Logger.writelnErr("Init reConnect");
            try {
                this.disconnect(false);
            } catch (Exception ex0) { Logger.writelnErr(ex0.getMessage()); }
            Logger.writelnErr("Stop all listners... wait 60 secounds...");
            Thread.sleep(60000);
            this.connection = null;
            Logger.writelnErr("Login to:"+SERVER+":"+PORT+"\nUIN: "+UIN);
            this.connection = new OscarConnection(SERVER, PORT, UIN, PASSWORD, null);
            connection.addMessagingListener(this);
            connection.addUserStatusListener(this);
            connection.addOurStatusListener(this);
            connection.connect();
        } catch (Exception ex) { Logger.writelnErr(ex.getMessage()); }
    }

    public void onMessageAck(MessageAckEvent e) {
    	 Logger.writelnErr("MessageAck " + e.getRcptUin());
    }

    public void onAuthorizationFailed(LoginErrorEvent e) {
         Logger.writelnErr("Authorization Failed! You UIN or Password is not valid");
    }

    public String getState()
    { return WELCOME_MSG; }


    public void onLogout(Exception exception) {
        try {
                Logger.writelnErr("ReConnect #0\nReconnect on 60 secounds...");
                Thread.sleep(60000);
                this.reConnect();
        } catch (Exception ex) {
            try {
                Logger.writelnErr("ReConnect #1\n"+ex.getMessage()+"\nReconnect on 60 secounds...");
                Thread.sleep(60000);
                this.reConnect();
            } catch (Exception ex1) { Logger.writelnErr(ex1.getMessage()+"\nLogged out (possibly due to error)"); ex1.printStackTrace(); System.out.println("Logged out (possibly due to error)"); }
        } Logger.writelnErr("ReConnect #X");
    }

    public void onLogin() {
       // Start Frame of Mind...
        new FrameOfMind(this);
        try {
            OscarInterface.changeStatus(this.connection, new StatusModeEnum(StatusModeEnum.INVISIBLE));
            Thread.sleep(3000);
            OscarInterface.changeStatus(this.connection, new StatusModeEnum(StatusModeEnum.EVIL));
            Thread.sleep(3000);
            OscarInterface.changeStatus(this.connection, new StatusModeEnum(StatusModeEnum.FREE_FOR_CHAT));
            // Запросим сообщения, присланные нам в оффлайн
            OscarInterface.requestOfflineMessages(this.connection);
            Thread.sleep(100);
            this.WELCOME_MSG="Инфхель ICQ Онлайн: "+SERVER+":"+PORT+"; UIN: "+UIN+"; Старт: "+new Date().toLocaleString();
            OscarInterface.sendBasicMessage(this.connection, MASTER_UIN,WELCOME_MSG);
        } catch (Exception ex) {Logger.writelnErr(ex.getMessage());}
    }

    public void onStatusResponse(StatusEvent e) {
        //throw new UnsupportedOperationException("Not supported yet.");
    }

    public void run() {
        try {
            Logger.writelnErr("Login to:"+SERVER+":"+PORT+"\nUIN: "+UIN);
            this.connection = new OscarConnection(SERVER, PORT, UIN, PASSWORD);
            connection.addMessagingListener(this);
            connection.addUserStatusListener(this);
            connection.addOurStatusListener(this);
            connection.connect();
        }
        catch (Exception ex) {Logger.writelnErr(ex.getMessage());}
    }

    public void onUpdateContactList(ContactListEvent event) {
        //throw new UnsupportedOperationException("Not supported yet.");
    }

    public void onSsiModifyingAck(SsiModifyingAckEvent event) {
        //throw new UnsupportedOperationException("Not supported yet.");
    }

    public void onSsiFutureAuthGrant(SsiFutureAuthGrantEvent event) {
        //throw new UnsupportedOperationException("Not supported yet.");
    }

    public void onSsiAuthRequest(SsiAuthRequestEvent event) {
        //throw new UnsupportedOperationException("Not supported yet.");
    }

    public void onSsiAuthReply(SsiAuthReplyEvent event) {
        //throw new UnsupportedOperationException("Not supported yet.");
    }
}